// https : // iai.sh.cn/problem/374
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int MOD = (int)1e9 + 7;
const int maxn = 300000 + 5;

LL res[maxn][67] = {0}; // 备忘
// 求组合数
LL C(LL n, LL m) {
  if (m == 0 || m == n)
    return 1;
  if (res[n][m] != 0)
    return res[n][m];
  return res[n][m] =
             (C(n - 1, m) + C(n - 1, m - 1)) % MOD; // 赋值给res[n][m]并返回
}

LL C1(LL n, LL m) {
  LL ans = 1;
  for (LL i = 1; i <= m; i++) {
    ans = ans * (n - m + i) % MOD / i % MOD; // 注意一定要先乘再除

    // 这个地方错了  (a/b) % MOD != .....
  }
  return ans % MOD;
}
// 求得的最大公约数正值
int gcd(int a, int b) { return b ? gcd(b, a % b) : abs(a); }

// 不建议用建立一个double到int的映射,
using pii = std ::pair<int, int>;
std ::map<pii, int> m;

int main() {

  int n;
  scanf("%d", &n);
  for (int i = 1; i <= n; ++i) {
    int a, b, c;
    scanf("%d %d %d", &a, &b, &c);

    if (a == 0)
      b = 1;
    else if (b == 0)
      a = 1;
    else {
      int d = gcd(a, b);
      a /= d;
      b /= d;
      // 题目数据没有考虑(2,-1) (-2,1)是平行线。
      if (b < 0)
        a = -a, b = -b;
    }
    // 统计每一种斜率的直线的数目
    m[std ::make_pair(a, b)]++;
  }

  LL ans = C(n, 3) % MOD;
  for (auto it : m) {
    int cnt = it.second;

    if (cnt >= 2)
      ans -= C(cnt, 2) * (n - cnt) % MOD;
    if (cnt >= 3)
      ans -= C(cnt, 3) % MOD;
    (ans += MOD) %= MOD;
  }

  printf("%lld\n", ans);
  return 0;
}